package ar.edu.itba.it.cg.grupo01.impl.shape;

import static com.google.common.base.Preconditions.checkNotNull;

import java.awt.Color;
import java.util.ArrayList;
import java.util.List;

import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;

import ar.edu.itba.it.cg.grupo01.api.Intersection;
import ar.edu.itba.it.cg.grupo01.api.Ray;
import ar.edu.itba.it.cg.grupo01.api.shape.Shape;
import ar.edu.itba.it.cg.grupo01.impl.IntersectionFactory;

public class Box extends AbstractShape {
	
	private Point3d vmin;
	private Point3d vmax;

	public Box(final Point3d vmin, final Point3d vmax,
			IntersectionFactory intersectionFactory) {
		this(vmin, vmax, intersectionFactory, null);
	}
	
	public Box (final Point3d vmin, final Point3d vmax,
			IntersectionFactory intersectionFactory, Color color) {
		super(intersectionFactory, color);
		// TODO: check arguments
		this.vmin = vmin;
		this.vmax = vmax;
	}

	@Override
	public Intersection<? extends Shape> intersects(final Ray ray) {
		
		checkNotNull(ray, "Ray should not be null");
		
		Vector3d dir = ray.getDirection();
		
		Vector3d invDir = new Vector3d(1.0/dir.x, 1.0/dir.y, 1.0/dir.z);
		boolean signDirX = invDir.x < 0;
		boolean signDirY = invDir.y < 0;
		boolean signDirZ = invDir.z < 0;
		
		Point3d bbox = signDirX ? vmax : vmin;
        double tmin = (bbox.x - ray.getOrigin().x) * invDir.x;
        bbox = signDirX ? vmin : vmax;
        double tmax = (bbox.x - ray.getOrigin().x) * invDir.x;
        bbox = signDirY ? vmax : vmin;
        double tymin = (bbox.y - ray.getOrigin().y) * invDir.y;
        bbox = signDirY ? vmin : vmax;
        double tymax = (bbox.y - ray.getOrigin().y) * invDir.y;

        if ((tmin > tymax) || (tymin > tmax)) {
                return intersectionFactory.emptyIntersection();
        }
        if (tymin > tmin) {
                tmin = tymin;
        }
        if (tymax < tmax) {
                tmax = tymax;
        }

        bbox = signDirZ ? vmax : vmin;
        double tzmin = (bbox.z - ray.getOrigin().z) * invDir.z;
        bbox = signDirZ ? vmin : vmax;
        double tzmax = (bbox.z - ray.getOrigin().z) * invDir.z;

        if ((tmin > tzmax) || (tzmin > tmax)) {
                return intersectionFactory.emptyIntersection();
        }
        if (tzmin > tmin) {
                tmin = tzmin;
        }
        if (tzmax < tmax) {
                tmax = tzmax;
        }
        
        if (tmin < 0)
        	return intersectionFactory.emptyIntersection();
        
        // intersection points
		List<Point3d> points = new ArrayList<Point3d>();
		points.add(ray.calculatePoint(tmin));
		// TODO: add exit point?
		
		return intersectionFactory.createIntersection(points);
	}

}
